package simplelab;

import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
/*
 * The information about the tile's of the world is stored
 * in this class.
 */

//utolsó helyen fordulás felesleges
//előre, körbe fordul maximális
//falakat belevegye a számolásba
//ha mégse venné fel a kaját az ellenfél, akkor visszamenjen
//doksi
//mackró cellák
//debug
//
public class World { 

    public final static int worldWidth = 60;
    public final static int worldHeigth = 60;
    public final static int maxEatPerTurn = 200;
    public final static int foodLostPerTurn = 50;
    public final static int lowEnergy = 200;
    public final static int considerIntelAgeValid = 8;
    public final static int maxFoods = 4;
    public final static int stepCost = 5;
    public final static int turnCost = 2;
    public final static int foodlessTurnLimit = 30;
    public static int turnsSinceLastFoodAction = -120;
    public static int turn = -1; // The turn we are in, from our perception
    public Tile[][] tile;
    public int lastChangeTurn;
    public boolean[][] points = new boolean[worldHeigth][worldWidth];
    public int lastEnemyPoint;
    public static DebugMap debugMap;
    public boolean enemyOnFood;
    public ArrayList<Agent> Friendlies;
    public ArrayList<Agent> Hostiles;
    public boolean myTeamIDSet;
    public int myTeamID;
    public int leaderID;
    public int tasksGiven;
    public int teamEnergy;
    public static Point position;
    public int eating;
    public Point myTarget;
    public static ArrayList<Food> Foods;
    public Task mainTask;
    public Tile[][] macroblock;
    public static int macro = 2;
    public boolean[][] macroPoints = new boolean[worldHeigth / macro][worldWidth / macro];
    Point[] mypos = new Point[deepness - 1];
    public boolean[][][] mytile = new boolean[deepness - 1][worldWidth][worldHeigth];
    public final static int deepness = 10;
    private boolean kettomely = true;
    private boolean guiOn = false;
    public boolean eredeti = false;
    private int lastTurn = 2;
    boolean aSearch = false;
    public boolean macroblocks = true;

    //public int onFood;
    // Defines wich checkPoint should the non-leader agents aim
   /* public int rotationState;
    public int timeBeforeRotation;
    public int timeSinceRotation;
     */
    public World() {
        tile = new Tile[worldWidth][worldHeigth];
        for (int x = 0; x < worldWidth; x++) {
            for (int y = 0; y < worldHeigth; y++) {
                tile[x][y] = new Tile();
            }
        }
        macroblock = new Tile[worldWidth / macro][worldHeigth / macro];
        for (int x = 0; x < worldWidth / macro; x++) {
            for (int y = 0; y < worldHeigth / macro; y++) {
                macroblock[x][y] = new Tile();
            }
        }

        for (int k = 0; k < worldHeigth / macro; k++) {
            for (int l = 0; l < worldWidth / macro; l++) {
                macroPoints[k][l] = false;
            }
        }

        for (int k = 0; k < worldHeigth; k++) {
            for (int l = 0; l < worldWidth; l++) {
                points[k][l] = false;
            }
        }

        for (int i = 0; i < deepness - 1; i++) {
            mypos[i] = new Point();
        }
        lastChangeTurn = deepness;
        if(guiOn){
            debugMap = new DebugMap(this);
        }
        /* Friendlies = new ArrayList<Agent>();
        Hostiles = new ArrayList<Agent>();*/
        Foods = new ArrayList<Food>();
        myTeamIDSet = false;
        myTeamID = -1;
        leaderID = 0;
        tasksGiven = 0;
        eating = 0;
        myTarget = new Point(-1, -1);
        // onFood= -1;
        lastEnemyPoint = 20000;
        enemyOnFood = false;
        /*rotationState = 0;
        timeSinceRotation = -100;
        timeBeforeRotation = 40;
         */
    }

    public static void error() {
        if (!Foods.isEmpty()) {
            int temp = min(position);
            if (min(position) % 1000 == 0) {
                Foods.remove(temp / 1000);
            }
        }

    }

    public static void errorBlock() {
        if (!Foods.isEmpty()) {
            int temp = min(position);
            // if(manhattan(pos, Foods.get(temp)) ==1){
            Foods.remove(temp / 1000);
            //}
        }

    }
   
    
    private boolean notInsideFood(Food food) {
       int  size = Foods.size();
       for(int i = 0; i<size ;i++){
           if(Foods.get(i).position.x ==food.position.x && Foods.get(i).position.y ==food.position.y){
               return false;
           }
       }
        
        return true;
    }

    public class FoodComp implements Comparator<Food> {

        @Override
        /* public int compare(Food o1, Food o2) {
        return o1.position.x<o2.position.x ;
        }*/
        public int compare(Food o1, Food o2) {
            if (o1.position.x < o2.position.x) {
                return -1;
            } else if (o2.position.x > o2.position.x) {
                return 1;
            } else {
                return 0;
            }
        }
    }

    public void foodManages(Beliefs beliefs) {
        //foodDelete(beliefs.pos, beliefs.dir);
        int size = beliefs.foods.size();
        for (int i = 0; i < size; i++) {
            if(notInsideFood(beliefs.foods.get(i))){
                Foods.add(beliefs.foods.get(i));
            }
        }
        //Collections.sort(Foods, new FoodComp());

        /***for(int i = 0; i< Foods.size(); i++){
        System.out.println(Foods.get(i).position + " ffsdfdsfdsfdsffsdfwe2w3w ");
        }***/
    }

    public void foodDelete(Point pos, int dir) {
        /****System.out.println(Foods.size() + " sddsfsfd "+ pos);
        for(int i = 0; i< Foods.size(); i++){
        System.out.println(Foods.get(i).position + " fff ");
        }***/
        int plus = 1, temp;
        if (dir == 0 || dir == 3) {
            plus = -1;
        }
        for (int i = 0; i < Foods.size(); i++) {

            if (dir % 2 == 0) {
                temp = (Foods.get(i).position.y - pos.y) * plus;
                if (temp > -1 && temp < 12 && Math.abs(Foods.get(i).position.x - pos.x) < temp + 1) {

                    ///System.out.println("0t�r�lve: "+ Foods.get(i).position.x + " y "+ Foods.get(i).position.y );
                    Foods.remove(i);
                    --i;
                }
            } else {
                temp = (Foods.get(i).position.x - pos.x) * plus;
                if (temp > -1 && temp < 12 && Math.abs(Foods.get(i).position.y - pos.y) < temp + 1) {
                    ///System.out.println("1t�r�lve: "+ Foods.get(i).position.x + " y "+ Foods.get(i).position.y );
                    Foods.remove(i);
                    --i;
                }

            }
        }
        /***
        System.out.println(Foods.size() + " sddsfdsfdsdfdsfdsfdfdssfd "+ pos);
        System.out.println(Foods.size() + " qwewqefsfd "+ pos);
        for(int i = 0; i< Foods.size(); i++){
        System.out.println(Foods.get(i).position + " fff ");
        }***/
    }

    //visszaadja a legk�zelebbi kaja sorsz�m�t
    //ha a rajta �ll, akkor a sorsz�mmalával*1000 t�r vissza
    //egyégként pedig a távolság és a sorszám*1000-rel
    public static int min(Point pos) {
        int temp = 0;
        int min = manhattan(pos, Foods.get(0).position);
        for (int i = 1; i < Foods.size(); i++) {
            if (manhattan(pos, Foods.get(i).position) < min) {
                temp = i;
                min = manhattan(pos, Foods.get(i).position);
            }
        }
        if (min == 0) {

            return temp * 1000;
        }
        return (min + (temp * 1000));
    }

    public Command Manage(Beliefs beliefs) {
        /*int asdf=0;
        for(int i = 0; i< 60; i++)
        for(int l = 0; l< 60; l++)
        asdf+= tile[i][l].value;*/

        MyTeamID(beliefs.team);
        position = beliefs.pos;
        lastChangeTurn++;

        //a frissítés (refreshTile) után 4 körig még megengedi a hátra forgást, ez a változó ezt szabályozza
        /// System.out.println("sdf " + eating);
        eating--;
        //turn = beliefs.

        if (beliefs.energy < lowEnergy) {
            return new Command(Command.Action.Wait, 0, 0);
        }

        teamEnergy = beliefs.energy;
        int enemyPoint = (int) (teamEnergy / beliefs.ratio) - teamEnergy;
        ///System.out.println(enemyPoint + " asd "+ lastEnemyPoint + " akdsjfa "+ teamEnergy+ " ratio "+beliefs.ratio);
        //átállítja ha az ellenség kajálni kezd
        if (enemyPoint > lastEnemyPoint + maxEatPerTurn / 4) {
            enemyOnFood = true;
        } else {
            //ha befejezte az ellenség a kajálást, frissít
            if (enemyOnFood) {
                refreshTiles();
                /***System.out.println(" enemy");
                System.out.println(enemyPoint + " az most "+ lastEnemyPoint);***/
            }
            enemyOnFood = false;
        }

        lastEnemyPoint = enemyPoint;
        //ha maxfood+1 akkor kaj�l
        if (beliefs.foods.size() > 0) {
            foodManages(beliefs);
            //System.out.println(onFood +" d " + Foods.get(0).value);

            int temp = min(beliefs.pos);
            if (temp % 1000 == 0) {
                int real = temp / 1000;
                Foods.get(real).value -= maxEatPerTurn + foodLostPerTurn;
                ///System.out.println(Foods.get(temp-100).value + " ennyi vazze "+  beliefs.foods.get(0).value);

                //kit�rli ha a k�r v�gi �tkez�s ut�n a kaja �rt�ke 1 al� cs�kkent

                if (Foods.get(real).value < 1) {
                    Foods.remove(real);

                    ///System.out.println(" manage");
                    refreshTiles();
                }
                return new Command(Command.Action.Eat, 0, 0);
            }


        }
        //megkeresi a k�vetkez� kaj�t
        if (Foods.size() > 0) {
            mainTask = findTarget(beliefs.pos, beliefs.agents, beliefs.dir);
        } else {
            //ha az utolsó körben sikerült lefutnia egy combinatenek és még van pár lépés benne akkor nem változtatja
            if (lastChangeTurn > lastTurn) {
                //OneTile(beliefs.pos, beliefs.dir);
                mainTask = Combinate(beliefs.pos, beliefs.dir);
                lastChangeTurn = 0;
            }
        }


        if (!mainTask.task.isEmpty()) {

            beliefs.dir = makeItNull(beliefs.pos, beliefs.dir, mainTask);
            if (guiOn) {
                debugMap.mcanvas.paint(debugMap.mcanvas.getGraphics(), beliefs.pos, beliefs.dir, Foods);
            }
            int mainTaskX = mainTask.task.get(0).x;
            int mainTaskY = mainTask.task.get(0).y;
            mainTask.task.remove(0);
            /*return new Command((mainTaskX == 0)
            ? Command.Action.Step : (mainTaskX == 1) ? Command.Action.Turn : Command.Action.Eat,
            mainTaskY, 0);*/
            if (mainTaskX == 0) {
                return new Command(Command.Action.Step, mainTaskY, 0);
            } else if (mainTaskX == 1) {
                return new Command(Command.Action.Turn, mainTaskY, 0);
            } else {
                return new Command(Command.Action.Eat, mainTaskY, 0);
            }
        } else {
            return new Command(Command.Action.Step, 0, 0);
        }

    }

    /*public Task recursion(int deepness, int currentDeepness, ArrayList<int> attribute){
    for(int n = 0; n < 4; ++n){
    int[] temp = {i,l,j,k,n};
    tempTask = CalculateTile(pos, dir, temp);
    if(tempTask.profit> maxProfit.profit)
    maxProfit = tempTask;
    }
    
    }*/
    //kikeresi a legk�zelebbi kaj�t
    private Task findTarget(Point pos, ArrayList<Agent> enemy, int dir) {
        int onFood = min(pos);
        /*** System.out.println(Foods.size() + " asdf ");
        for(int i= 0; i < Foods.size();i++)
        System.out.println(Foods.get(i).position + " asfdsasdf ");***/
        int temp = onFood / 1000;
        if (onFood % 1000 == 0) {

            Task ret = new Task();
            Foods.get(temp).value -= maxEatPerTurn + foodLostPerTurn;
            if (Foods.get(temp).value < 1) {
                Foods.remove(temp);
                /// System.out.println(" find target");
                refreshTiles();
            }

            ret.task.add(new Point(3, 0));
            return ret;
        }
        return findPath(pos, Foods.get(temp), enemy, dir);
    }
    //meghat�rozza az utat a kaj�ig

    private Task findPath(Point pos, Food closest, ArrayList<Agent> enemy, int dir) {
        Task ret = new Task();

        if (aSearch) {
            int dirx = -1, diry = -1;
            if (closest.position.x > pos.x) {
                dirx = 1;
            } else if (closest.position.x < pos.x) {
                dirx = 3;
            } else if (closest.position.y > pos.y) {
                diry = 2;
            } else if (closest.position.y < pos.y) {
                diry = 0;
            }
            
            
        }
        Point enemyPos = null;
        if (enemy != null && enemy.size() > 0) {
            int n = 0;
            for (int i = 0; i < enemy.size(); i++) {
                if (enemy.get(i).team != myTeamID) {
                    enemyPos = enemy.get(i).position;
                    n = i;
                }
            }
            //System.out.println(" itt van " + enemy.size());
            if (min(enemyPos) % 1000 == 0) {
                for (int l = 0; l < Foods.size(); l++) {
                    if (enemyPos.x == Foods.get(l).position.x && enemyPos.y == Foods.get(l).position.y) {
                        Foods.remove(l);
                        if (Foods.size() > 0) {
                            return findTarget(pos, enemy, dir);
                        } else {
                            return Combinate(pos, dir);
                        }
                    }
                }

            } else if (manhattan(enemyPos, closest.position) < manhattan(pos, closest.position) && enemy.get(n).IsFacing(closest.position)) {
                // System.out.println(" törlés előtt "+Foods.size());
                Foods.remove(closest);
                // System.out.println(" törlés utn "+Foods.size());
                if (Foods.size() > 0) {
                    return findTarget(pos, enemy, dir);
                } else {
                    return Combinate(pos, dir);
                }
            }

        }
        Point tempPoint = null;
        if (closest.position.x > pos.x) {
            tempPoint = new Point(0, 1);
        } else if (closest.position.x < pos.x) {
            tempPoint = new Point(0, 3);
        } else if (closest.position.y > pos.y) {
            tempPoint = new Point(0, 2);
        } else if (closest.position.y < pos.y) {
            tempPoint = new Point(0, 0);
        }
        //else{
        //Foods.get(Foods.indexOf(closest)).value -= maxEatPerTurn;
        //ret.task.add(new Point(3,0));
        //}    
        if (tempPoint.y != dir) {
            ret.task.add(new Point(1, tempPoint.y));
        } else {
            ret.task.add(tempPoint);
        }
        //ret.task.add(pos);

        return ret;
    }

    public static int manhattan(Point first, Point second) {
        return Math.abs(first.x - second.x) + Math.abs(first.y - second.y);

    }

    //visszaadja a megadott l�p�sek sor�n �rintett mez�k �ssz�rt�k�t
    /*public Task CalculateTile(Point pos, int dir, int[] actions, int turnCount) {
        int plus;
        Point tempPos = new Point();

        Task returner = new Task();
        //megmondja hogy x tengelyre párhuzamos-e a dir
        boolean dirx;
        tempPos.x = pos.x;
        tempPos.y = pos.y;
        //segéd változók a az adott pont kiszámításához
        int tempX = 0, tempY = 0;
        for (int k = 0; k < deepness; k++) {
            /**
             * actions: 
             * 0 move forward
             * 1 turn right
             * 2 turn back
             * 3 turn left
             */
            /*if (actions[k] != 0) {
                dir = (dir + actions[k]) % 4;

                returner.task.add(new Point(1, dir));

            }
            //how the pos will change
            if (dir == 2 || dir == 1) {
                plus = 1;
            } else {
                plus = -1;
            }

            dirx = (dir % 2 == 0);

            //pos moving
            if (actions[k] == 0) {
                if (dirx) {
                    tempPos.y += plus;
                } else {
                    tempPos.x += plus;
                }
                returner.task.add(new Point(0, dir));
            }

            //put the title
            for (int i = 1; i < 11; ++i) {
                if (dirx) {
                    tempY = tempPos.y + plus * i;
                } else {
                    tempX = tempPos.x + plus * i;
                }
                for (int l = -1 * i; l <= i; ++l) {
                    if (dirx) {
                        tempX = tempPos.x + l;
                    } else {
                        tempY = tempPos.y + l;
                    }
                    if (tempX > -1 && tempX < worldWidth && tempY > -1 && tempY < worldHeigth) {
                        points[tempX][tempY] = true;
                    }
                    //ha kifele néz else if()
                }
            }

        }
        //bool t�mb, 
        for (int i = 0; i < worldHeigth; i++) {
            for (int l = 0; l < worldWidth; l++) {
                if (points[i][l]) {
                    returner.profit += tile[i][l].value;
                    points[i][l] = false;
                }
            }
        }
        returner.profit /= ((deepness - turnCount) * stepCost + turnCount * turnCost);
        return returner;




    }*/

    public Task CalculateMacro(Point pos, int dir, int[] actions, int turnCount) {
        int plus;
        Point tempPos = new Point();

        Task returner = new Task();
        //megmondja hogy x tengelyre párhuzamos-e a dir
        boolean dirx;
        tempPos.x = pos.x / macro;
        tempPos.y = pos.y / macro;
        //segéd változók a az adott pont kiszámításához
        int tempX = 0, tempY = 0;
        for (int k = 0; k < deepness; k++) {
            /**
             * actions: 
             * 0 move forward
             * 1 turn right
             * 2 turn back
             * 3 turn left
             */
            if (actions[k] != 0) {
                dir = (dir + actions[k]) % 4;

                returner.task.add(new Point(1, dir));

            }
            //how the pos will change
            if (dir == 2 || dir == 1) {
                plus = 1;
            } else {
                plus = -1;
            }

            dirx = (dir % 2 == 0);

            //pos moving
            if (actions[k] == 0) {
                if (dirx) {
                    tempPos.y += plus;
                } else {
                    tempPos.x += plus;
                }
                returner.task.add(new Point(0, dir));
            }

            //put the title
            for (int i = 1; i < 10 / macro + 1; ++i) {
                if (dirx) {
                    tempY = tempPos.y + plus * i;
                } else {
                    tempX = tempPos.x + plus * i;
                }
                for (int l = -1 * i; l <= i; ++l) {
                    if (dirx) {
                        tempX = tempPos.x + l;
                    } else {
                        tempY = tempPos.y + l;
                    }
                    if (tempX > -1 && tempX < worldWidth / macro && tempY > -1 && tempY < worldHeigth / macro) {
                        macroPoints[tempX][tempY] = true;

                    }
                    //ha kifele néz else if()
                }
            }

        }
        //bool t�mb, 
        for (int i = 0; i < worldHeigth / macro; i++) {
            for (int l = 0; l < worldWidth / macro; l++) {
                ///System.out.print(macroblock[i][l].value + " ");
                if (macroPoints[i][l]) {
                    returner.profit += macroblock[i][l].value;
                    macroPoints[i][l] = false;
                }
            }
            /// System.out.println();
        }
        returner.profit = returner.profit * 10 / ((deepness - turnCount) * stepCost + turnCount * turnCost);
        return returner;




    }

    private boolean inSide(int[] tempDeep, Point pos, int dir) {
        int plus;
        int i = 0;
        boolean dirx;
        int tempX = pos.x, tempY = pos.y;
        do {
            if (tempDeep[i] != 0) {
                dir = (dir + tempDeep[i]) % 4;
            }
            //how the pos will change
            if (dir == 2 || dir == 1) {
                plus = 1;
            } else {
                plus = -1;
            }
            dirx = dir % 2 == 0;
            //pos moving
            if (tempDeep[i] == 0) {
                if (dirx) {
                    tempY += plus;
                } else {
                    tempX += plus;
                }
            }
        } while (i++ < tempDeep.length - 1 && !((tempY > worldHeigth - 10 && dir == 2)
                || (tempY < 10 && dir == 0) || (tempX > worldWidth - 10 && dir == 1)
                || (tempX < 10 && dir == 3)));
        if (i == tempDeep.length) {
            return true;
        }
        return false;
    }

    /*private boolean inSideMacro(int[] tempDeep, Point pos, int dir) {
        int plus;
        int i = 0;
        boolean dirx;
        int tempX = pos.x, tempY = pos.y;
        do {
            if (tempDeep[i] != 0) {
                dir = (dir + tempDeep[i]) % 4;
            }
            //how the pos will change
            if (dir == 2 || dir == 1) {
                plus = 1;
            } else {
                plus = -1;
            }
            dirx = dir % 2 == 0;
            //pos moving
            if (tempDeep[i] == 0) {
                if (dirx) {
                    tempY += plus;
                } else {
                    tempX += plus;
                }
            }
        } while (i++ < tempDeep.length - 1 && !((tempY > (worldHeigth - 10) && dir == 2)
                || (tempY < 10 / macro && dir == 0) || (tempX > (worldWidth - 10) && dir == 1)
                || (tempX < 10 / macro && dir == 3)));
        if (i == tempDeep.length) {
            return true;
        }
        return false;
    }*/

    /*public Task ReCombinate(int deep, Point pos, int dir, int[] temp) {
        Task tempTask, maxProfit = new Task();




        int z = 2;
        //a kaja utáni első három körben a hátrafordulás is engedélyezett
        if (eating > 0) {
            z = 1;
            ///System.out.println(" it " + eating);
        }
        //int posY = pos.y, posX = pos.x;
        int[] tempDeep = new int[deepness];
        for (int i = 0; i < deepness; ++i) {
            tempDeep[i] = 0;
        }
        maxProfit = CalculateTile(pos, dir, tempDeep, 0);
        for (int i = deepness - 4; i > -1; --i) {
            for (int n = 1; n < 4; n += z) {
                tempDeep[i] = n;
                if (inSide(tempDeep, pos, dir)) {
                    tempTask = CalculateTile(pos, dir, tempDeep, 1);
                    if (tempTask.profit > maxProfit.profit) {
                        maxProfit = tempTask;
                        /* System.out.println(maxProfit.profit+" "+deep+ " "+deepness+ " "+tempDeep[0] );
                        for(int k = 0; k<deepness;++k){
                        System.out.print(tempDeep[k]+ " ");
                        }
                        System.out.println();*/
                  /*  }
                }
            }
            tempDeep[i] = 0;
        }
        if (kettomely) {
            for (int i = deepness - 4; i > -1; --i) {

                for (int n = 1; n < 4; n += z) {
                    tempDeep[i] = n;
                    for (int l = deepness - 1; l > i; --l) {
                        for (int j = 1; j < 4; j += z) {
                            tempDeep[l] = j;
                            if (inSide(tempDeep, pos, dir)) {
                                tempTask = CalculateTile(pos, dir, tempDeep, 2);
                                if (tempTask.profit > maxProfit.profit) {
                                    maxProfit = tempTask;
                                    
                                }
                            }
                        }
                        tempDeep[l] = 0;
                    }

                }
                tempDeep[i] = 0;
            }


        }

        ///System.out.println(pos+ " hopp� ");
        //}
        return maxProfit;
    }*/

    public Task ReCombinateMacro(int deep, Point pos, int dir, int[] temp) {
        Task tempTask, maxProfit = new Task();




        int z = 2;
        //a kaja utáni első három körben a hátrafordulás is engedélyezett
        if (eating > 0) {
            z = 1;
            ///System.out.println(" it " + eating);
        }
        //int posY = pos.y, posX = pos.x;
        int[] tempDeep = new int[deepness];
        for (int i = 0; i < deepness; ++i) {
            tempDeep[i] = 0;
        }
        maxProfit = CalculateMacro(pos, dir, tempDeep, 0);
        for (int i = deepness - 4; i > -1; --i) {
            for (int n = 1; n < 4; n += z) {
                tempDeep[i] = n;
                if (inSide(tempDeep, pos, dir)) {
                    tempTask = CalculateMacro(pos, dir, tempDeep, 1);
                    if (tempTask.profit > maxProfit.profit) {
                        maxProfit = tempTask;
                    }
                }
            }
            tempDeep[i] = 0;
        }
        if (kettomely) {
            for (int i = deepness - 4; i > -1; --i) {

                for (int n = 1; n < 4; n += z) {
                    tempDeep[i] = n;
                    for (int l = deepness - 1; l > i; --l) {
                        for (int j = 1; j < 4; j += 2) {
                            tempDeep[l] = j;
                            if (inSide(tempDeep, pos, dir)) {
                                tempTask = CalculateMacro(pos, dir, tempDeep, 2);
                                if (tempTask.profit > maxProfit.profit) {
                                    maxProfit = tempTask;
                                }
                            }
                        }
                        tempDeep[l] = 0;
                    }

                }
                tempDeep[i] = 0;
            }


        }

        ///System.out.println(pos+ " hopp� ");
        //}
        return maxProfit;
    }

    public Task Combinate(Point pos, int dir) {
        Task maxProfit, tempTask;
        maxProfit = new Task();
        /*if (!macroblocks) {
            maxProfit = ReCombinate(0, pos, dir, null);
            if (maxProfit.profit == 0) {
                for (int i = 0; i < worldHeigth; i++) {
                    for (int l = 0; l < worldWidth; l++) {
                        tile[i][l].value = 4;
                    }
                }
                maxProfit = ReCombinate(0, pos, dir, null);
            }
        } else {*/
            maxProfit = ReCombinateMacro(0, pos, dir, null);
            if (maxProfit.profit == 0) {
                for (int i = 0; i < worldHeigth / macro; i++) {
                    for (int l = 0; l < worldWidth / macro; l++) {
                        macroblock[i][l].value = 4;
                    }
                }
                maxProfit = ReCombinateMacro(0, pos, dir, null);
            }
        //}
        return maxProfit;
    }

    //kinull�zza a l�tott mez�k �rt�k�t
    //átállítja a beliefseket, az akció utánira, azaz lépteti vagy elforgatja a nézetet
    //debugonhoz kell ez
    public int makeItNull(Point pos, int dir, Task maxProfit) {

        int plus;
        int maxProfitX = maxProfit.task.get(0).x,
                maxProfitY = maxProfit.task.get(0).y;


        // turning x = 1, y =  the dir
        if (maxProfitX == 1) {
            dir = maxProfitY;
        }
        //how the pos will change
        if (dir == 2 || dir == 1) {
            plus = 1;
        } else {
            plus = -1;
        }




        //lépésnél válozik a pozíció
        if (maxProfitX == 0) {
            if (maxProfitY % 2 == 0) {
                pos.y += plus;
            } else {
                pos.x += plus;
            }
        }
        if (!macroblocks) {
            int tempX = pos.x, tempY = pos.y;
            tile[tempX][tempY].value = 0;
            for (int i = 1; i < 11; ++i) {
                for (int l = -1 * i; l <= i; ++l) {
                    if (dir % 2 == 0) {
                        tempX = pos.x + l;
                        tempY = pos.y + plus * i;
                    } else {
                        tempX = pos.x + plus * i;
                        tempY = pos.y + l;
                    }
                    //System.out.println(tempX+ "po" + tempY + "asdfdsa"+ pos.x+ " "+pos.y +" " + plus);
                    if (tempX > -1 && tempX < worldWidth && tempY > -1 && tempY < worldHeigth) {
                        tile[tempX][tempY].value = 0;
                    }

                }
            }
        } else {
            int tempX = (pos.x) / macro, tempY = (pos.y) / macro;
            ///System.out.println(tempX+ "    dsfd   " + tempY);
            macroblock[tempX][tempY].value = 0;
            for (int i = 1; i < 10 / macro + 1; ++i) {
                for (int l = -1 * i; l <= i; ++l) {
                    if (dir % 2 == 0) {
                        tempX = pos.x / macro + l;
                        tempY = pos.y / macro + plus * i;
                    } else {
                        tempX = pos.x / macro + plus * i;
                        tempY = pos.y / macro + l;
                    }
                    /// System.out.println(tempX+ "po" + tempY + "asdfdsa"+ pos.x+ " "+pos.y +" " + plus);
                    if (tempX > -1 && tempX < worldWidth / macro && tempY > -1 && tempY < worldHeigth / macro) {
                        macroblock[tempX][tempY].value = 0;
                    }

                }
            }
        }
        return dir;
    }

    private void refreshTiles() {
        lastChangeTurn = deepness;
        eating = 4;
        if (!macroblocks) {
            for (int i = 0; i < worldHeigth; i++) {
                for (int l = 0; l < worldWidth; l++) {
                    if (tile[i][l].value < 4) {
                        tile[i][l].value++;
                    }
                }
            }
        } else {
            for (int i = 0; i < worldHeigth / macro; i++) {
                for (int l = 0; l < worldWidth / macro; l++) {
                    if (macroblock[i][l].value < 4) {
                        macroblock[i][l].value++;
                    }
                }
            }
        }
    }

    public void MyTeamID(int myTeamID) {
        if (myTeamIDSet == false) {
            this.myTeamID = myTeamID;
            myTeamIDSet = true;
        }
    }

    public void ManageHostileAgent(Agent agent) {
        // Is it really hostile?
        if (agent.team != myTeamID) {
            // Is agent on list?
            int i;
            for (i = 0; i < Hostiles.size() && Hostiles.get(i).id != agent.id; i++);
            if (i == Hostiles.size()) {
                Hostiles.add(agent);
            } else {
                Hostiles.get(i).RefreshIntel(agent);
            }
        }
    }

    /*public Agent ManageFriendlyAgent(Agent agent) {
    // Is it really friendly?
    if (agent.team == myTeamID) {
    // Is this the first agent?
    if (Friendlies.isEmpty()) {
    Friendlies.add(agent);
    leaderID = agent.id;
    AddInitialTask(agent);
    } else {
    // Is agent on list?
    int i;
    for (i = 0; i < Friendlies.size() && Friendlies.get(i).id != agent.id; i++);
    if (i == Friendlies.size()) {
    Friendlies.add(agent);
    AddInitialTask(agent);
    } else {
    Friendlies.get(i).RefreshIntel(agent);
    agent = Friendlies.get(i);
    }
    }
    // Manage Tile info
    if (tile[agent.position.x][agent.position.y].isVisited() == false
    && agent.inWater) {
    // Setting water hassle
    for (WorldIterator it = new WorldIterator(this, agent.position.x, agent.position.y,
    1, true, 1); it.IsNotEnd(); it.Next()) {
    tile[it.x][it.y].setWaterHassle(
    Heur.Manhattan(it.x, it.y, agent.position.x, agent.position.y));
    }
    // Recalculate checkpoints, based on new hassle values
    CalculateCheckpoints();
    // Setting water probability
    if (Heur.Manhattan(agent.position, agent.lastPosition) == 1) {
    int dx = agent.position.x - agent.lastPosition.x,
    dy = agent.position.y - agent.lastPosition.y;
    if (IsValidTile(agent.position.x + dx, agent.position.y + dy)) {
    if (tile[agent.lastPosition.x][agent.lastPosition.y].isWater) {
    tile[agent.position.x + dx][agent.position.y + dy].addWaterProbability(0.5);
    } else {
    tile[agent.position.x + dx][agent.position.y + dy].addWaterProbability(1.0);
    }
    }
    if (IsValidTile(agent.position.x + dy, agent.position.y + dx)) {
    tile[agent.position.x + dy][agent.position.y + dx].addWaterProbability(0.5);
    }
    if (IsValidTile(agent.position.x - dy, agent.position.y - dx)) {
    tile[agent.position.x - dy][agent.position.y - dx].addWaterProbability(0.5);
    }
    } else {
    // We were spawned in water, or pushed to water
    for (WorldIterator it = new WorldIterator(this, agent.position.x, agent.position.y,
    1, false, 1); it.IsNotEnd(); it.Next()) {
    tile[it.x][it.y].addWaterProbability(0.3);
    }
    }
    }
    // Refresh seen tiles
    Point p = new Point();
    for (WorldIterator it = new WorldIterator(this, agent.position.x, agent.position.y, 10,
    true, 0); it.IsNotEnd(); it.Next()) {
    p.setLocation(it.x, it.y);
    if (agent.CanSee(p)) {
    // Get enemy on that tile
    Agent enemy = null;
    for (int i = 0; i < Hostiles.size(); i++) {
    if (Hostiles.get(i).position.equals(p)) {
    enemy = Hostiles.get(i);
    }
    }
    tile[it.x][it.y].Refresh(enemy);
    }
    }
    // Visit this tile
    tile[agent.position.x][agent.position.y].Visit(agent.inWater);
    // If this is the leader, increase turns
    if (agent.id == leaderID) {
    Turn();
    }
    // Movement related stuff
    if (agent.lastPosition.equals(agent.position)) {
    agent.timeSpentHere++;
    } else {
    // We were attacked!
    if (Heur.Manhattan(agent.lastPosition, agent.position) > 1) {
    agent.GetTask().attacked++;
    }
    agent.timeSpentHere = 0;
    agent.turnsMade = 0;
    agent.waited = 0;
    }
    agent.lastPosition.setLocation(agent.position);
    }
    return agent;
    }
    
    
    
    public void AddInitialTask(Agent myAgent) {
    ExploreTask exploreTask = new ExploreTask(this, checkPoints.get(tasksGiven));
    exploreTask.assignedTo = myAgent;
    myAgent.tasks.add(exploreTask);
    tasksGiven++;
    if (tasksGiven > 1) {
    tasksGiven++;
    }
    }
    
    public void ValidateTasks() {
    // Clear invalid tasks from agents
    Agent myAgent = null;
    Task task = null;
    for (int i = 0; i < Friendlies.size(); i++) {
    myAgent = Friendlies.get(i);
    for (int k = 0; k < myAgent.tasks.size(); k++) {
    task = myAgent.tasks.get(k);
    if (task.IsValid() == false) {
    myAgent.tasks.remove(task);
    k--;
    }
    }
    }
    }
    
    public void MakeNewTasks() {
    // Search for eat tasks
    EatTask eatTask = null;
    while ((eatTask = EatTask.MakeNew(this)) != null) {
    AssignTask(eatTask);
    }
    // Search for heal tasks
    HealTask healTask = null;
    while ((healTask = HealTask.MakeNew(this)) != null) {
    AssignTask(healTask);
    }
    // Search for check tasks (we need only 1)
    CheckTask checkTask = CheckTask.MakeNew(this);
    if (checkTask != null) {
    AssignTask(checkTask);
    }
    }
    
    public void AssignTask(Task task) {
    Agent idealAgent = null;
    int lowestAvailability = -1, currentAvailability;
    for (int i = 0; i < Friendlies.size(); i++) {
    currentAvailability = task.AvailabilityFrom(Friendlies.get(i));
    if (lowestAvailability == -1 || currentAvailability < lowestAvailability) {
    lowestAvailability = currentAvailability;
    idealAgent = Friendlies.get(i);
    }
    }
    idealAgent.tasks.add(task); 
    task.assignedTo = idealAgent;
    }
    
    
    
    
    // Get direction required to look, from two points next to each other
    public int ToDir(Point from, Point to) {
    int x = to.x - from.x, y = from.y - to.y;
    if (y == 1) {
    return 0;
    } else if (x == 1) {
    return 1;
    } else if (y == -1) {
    return 2;
    }
    return 3;        
    }
    
    public Command Approach(Agent myAgent, Point goal) {
    // Am I blocked?
    if (IsTileFree(myAgent.position) == false) {
    myAgent.goalBlocked = false;
    myAgent.isBlocked = true;
    // Make the agent wait for a while
    WaitTask task = new WaitTask(this, 10, 30);
    task.assignedTo = myAgent;
    myAgent.tasks.add(task);
    return new Command(Command.Action.Wait, 0, 0);            
    } else if (IsTileFree(goal) == false) {
    // Is Goal blocked?
    myAgent.goalBlocked = true;
    myAgent.isBlocked = false;
    return new Command(Command.Action.Wait, 0, 0);            
    }
    myAgent.goalBlocked = false;
    myAgent.isBlocked = false;
    
    // Astar to build a route, with goal 'n'
    Node n = astar.NextStep(myAgent.position, goal);
    if (n == null) {
    // Routing error
    return new Command(Command.Action.Wait, 0, 0);
    }
    boolean dontTurn = false;
    
    while (n.reachedFrom.reachedFrom != null) {
    n = n.reachedFrom;
    }
    if (World.turn - tile[n.point.x][n.point.y].lastCheck <= 2) {
    dontTurn = true;
    }
    int desiredDirection = ToDir(myAgent.position, n.point);
    
    // Checking if turning is accurate for goal
    if (dontTurn == false && myAgent.direction != desiredDirection) {
    return new Command(Command.Action.Turn, desiredDirection, 0);
    }
    // Approaching goal
    return new Command(Command.Action.Step, desiredDirection, 0);
    }
    
    public Agent IsThereFriendly(Point position) {
    for (int j = 0; j < Friendlies.size(); j++) {
    if (Friendlies.get(j).position.equals(position)) {
    return Friendlies.get(j);
    }
    }
    return null;
    }
    
    public static int CalculateEdgeHassle(int x, int y) {
    int minEdgeDistance = Math.min(worldWidth - 1 - x,
    worldHeigth - 1 - y);
    minEdgeDistance = Math.min(minEdgeDistance, x);
    minEdgeDistance = Math.min(minEdgeDistance, y);
    if (minEdgeDistance < 10) {
    //return 10 - minEdgeDistance;
    return 5;
    }
    return 0;
    }
    
    public boolean IsRotationReady() {
    // We already know all the food, or the last rotation was recently
    if (Foods.size() >= 2 || timeSinceRotation < timeBeforeRotation) {
    return false;
    }
    int numberOfReadyAgents = 0;
    Agent agent = null;
    // Start from 1: skip the leader
    for (int i = 1; i < Friendlies.size(); i++) {
    agent = Friendlies.get(i);
    if (agent.turnsMade > 4 && agent.GetTask().priority == 1
    && Heur.Bird(agent.position, agent.GetTask().goal) <= 1) {
    numberOfReadyAgents++;
    }
    }
    if (numberOfReadyAgents >= UsefulAgents() - 2) {
    timeSinceRotation = 0;
    return true;
    }
    return false;
    }
    
    public int TeamEnergy() {
    int teamEnergy = 0;
    for (int i = 0; i < Friendlies.size(); i++) {
    teamEnergy += Friendlies.get(i).energy;
    }
    return teamEnergy;
    }
    
    private int UsefulAgents() {
    int useful = 0;
    for (int i = 0; i < Friendlies.size(); i++) {
    if (Friendlies.get(i).IsUseful()) {
    useful++;
    }
    }
    return useful;
    }
    
    private void Turn() {
    turn++;
    timeSinceRotation++;
    turnsSinceLastFoodAction++;
    }
    
    public Point AttackResult(Agent myAgent, Point pos) {
    Point result = (Point) pos.clone();
    Point attack = myAgent.AttackVector();
    result.setLocation(result.x + attack.x, result.y + attack.y);
    while (IsValidTile(result.x, result.y) && IsThereFriendly(result) == null
    && Heur.Manhattan(result, pos) <= 10) {
    result.setLocation(result.x + attack.x, result.y + attack.y);
    }
    result.setLocation(result.x - attack.x, result.y - attack.y);
    return result;
    }
    
    public boolean IsThereEnemy(Point pos) {
    Tile t = tile[pos.x][pos.y];
    if (t.lastEnemySeenHere == null) {
    return false;
    }
    if (t.lastEnemySeenHere.position.equals(pos)) {
    return World.turn - t.enemyWasHere <= considerIntelAgeValid;
    } else {
    t.lastEnemySeenHere = null;
    return false;
    }
    }
    
    public Agent GetEnemy(Point pos) {
    if (IsThereEnemy(pos)) {
    return tile[pos.x][pos.y].lastEnemySeenHere;
    }
    return null;
    }
    
    public static boolean IsValidTile(int x, int y) {
    if (x < 0 || x > worldWidth - 1 || y < 0 || y > worldHeigth - 1) {
    return false;
    }
    return true;
    }
    
    @Override
    public String toString() {
    String friendInfo = new String();
    for (int i = 0; i < Friendlies.size(); i++) {
    friendInfo += "    ID: " + Friendlies.get(i).id
    + "      Energy: " + Friendlies.get(i).energy
    + "\n        TaskPri: " + Friendlies.get(i).GetTask().priority
    + "  goal: " + Friendlies.get(i).GetTask().goal.x + "," 
    + Friendlies.get(i).GetTask().goal.y + "\n";
    }        
    return "myTeamIDSet: " + myTeamIDSet + "\n"
    + "leaderID: " + leaderID + "\n"
    + "tasksGiven: " + tasksGiven + "\n"
    + "Friendlies: " + Friendlies.size() + "\n"
    + friendInfo
    + "Hostiles: " + Hostiles.size() + "\n"
    + "Foods: " + Foods.size() + "\n"
    + "\n" + "TeamEnergy: " + TeamEnergy() + "\n"
    + "\n" + "teamTime: " + Knowledge.myTeamTimeLeft + "\n"
    + "turn: " + turn + "\n"
    + "lastEat: " + World.turnsSinceLastFoodAction + "\n";
    }*/
}
